from google.appengine.api.memcache import Client
from google.appengine.ext import db, webapp, webapp
from google.appengine.ext.db import polymodel
from google.appengine.ext.webapp import template, template, util
from google.appengine.ext.webapp.util import run_wsgi_app
from infra import facebook
import os
import os.path
import random
import wsgiref.handlers


#the aplication's facebook app-id and app-secret:
FACEBOOK_APP_ID = "187941941228345"
FACEBOOK_APP_SECRET = "38daa002a6bb69415a308eef25e7d695"
Default_Action = "home"


# gu modules:
class User(db.Model):
    ''' facebook user '''
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    
    id = db.StringProperty(required=True)
    name = db.StringProperty(required=True)
    profile_url = db.StringProperty(required=True)
    access_token = db.StringProperty(required=True)

# gu basic handler
class MyBaseHandler(webapp.RequestHandler):
    '''give all the basic utils for the handler'''
    
    # cache\session staff:
    def othersSessionGet(self,userIds,key):
        '''get some info from other users's sessions, using their userIds(key-name)'''
        res = []
        for userId in userIds:
            session = Client().get(userId)
            if session:
                res.append(session.get(key))
        return res
    
    def sessionSet(self,key,value):
        ''' put the value with key in the cache '''
        session = self.session 
        session[key] = value
        Client().set(self.current_user.key().name(),session)
    
    def sessionGet(self,key):
        '''get the value from the cahce by the key'''
        return self.session.get(key)
    
    def setToSession(self,key,d):
        '''set the d["key"] in cahce with key'''
        self.sessionSet(key,d.get(key))
    
    def getFromSession(self,key,d):
        '''get the value from the cahce by the key and put in dic.'''
        d[key] = self.sessionGet(key)
    
    @property
    def session(self):
        '''get the client session according to current user.'''
        session = Client().get(self.current_user.key().name())
        if not session:
            session = {}
        return session
    
  
    
    #get and post map to the right methods:
    
    def get(self,action):
        '''general get, map to the template-html and right method by the action name(url)'''
        
        # Ignore, fix some system bug:
        if action == "favicon.ico":
            return
        
        # if empty path set the defualt action.(define in the handler).    
        if action == '':
            action = Default_Action
        
		# handle request for string.
        if action.startswith("string-"):
            action = action.split("string-",1)[1]
            outputString = True
        else:
            outputString = False
        
        # if no model, send to general model.
        if not action.count("-"):                
            action = "general-" + action
        (model,modelAction) = action.split("-")
        
        
        # di - dictionry for input, fill with request args:
        self.di = {}
        for key in self.request.arguments(): self.di[key] =  self.request.get(key)
        # do - dictionary for output.
        self.do = {}
        
        #try to look for the method to run:
        theModel = None
        try:
            theModel = __import__(model)
        except :
            pass
        if theModel:
            method = getattr(theModel,modelAction)
            if method:
                method(h=self)
        #old:
        #getattr(__import__(model),modelAction)(h=self)
        
        # set the facebook app id and user in the output.
        self.do["facebook_app_id"] = FACEBOOK_APP_ID
        self.do["current_user"] = self.current_user
        
        # TODO: temp set alon as the admin
        ad = ["705046657","1031417530"]
        if self.current_user and self.current_user.key().name() in ad:
                self.do["admin"] = "true"
        
        # send output as string
        if outputString:
            self.response.out.write(self.do["output"])
        # send output as HTML
        else:
            self.sendResponse(__file__, '..//html//' + action + '.html', self.do)
    
    def post(self,action):
        ''' general post map to the right method by the action(url) '''
        # di - input-dictionary
        self.di ={}
        
        #fill dictionary input with request values.
        for key in self.request.arguments(): self.di[key] =  self.request.get(key)
        
        #new:
        if not action.count("-"):                
            action = "general-" + action
        (model,modelAction) = action.split("-")
        
        #run the method, according to acction:
        #getattr(self,action)(di=di)
        
        #new:
        getattr(__import__(model),modelAction)(h=self)
        
    def upsert(self,d,modelType):
        '''update or insert: update if exist(if got id in d), insert if new(else), fill model with d values and save.
            if you want to update give id or key_name in d.
            if you want to create new with sepecfic key_name, give spesific key_name
            else create new with id.
        '''
        
        # if d have key name used it
        if d.get("key_name"):
            #try get model by key name
            model = modelType.get_by_key_name(d.get("key_name"))
            #if not exist create with key name
            if not model:
                model = modelType(key_name=d.get("key_name")) 
        # if d have id get model by id               
        elif d.get("id"):
            model = modelType.get_by_id(int(d.get("id")))
        # else create a new model
        else:
            model = modelType()
        
        #for each attr in model try to get value form d in put in model
        for name in dir(modelType):
            value = d.get(name)
            if value:
                if getattr(modelType,name).__class__ == db.IntegerProperty:
                    value = int(value)
                if getattr(modelType,name).__class__ == db.BooleanProperty:
                    value = value == "True"
                setattr(model, name, value)
        #save model, return key
        model.put()
        return model 
    
    # facebook, get current user from cookie\db.
    @property
    def current_user(self):
        ''' facebook current user. gets from cookie or db(if already exist).'''
        
        #TODO:temp - only in devlopment:##
#        rand = ""#random.choice(range(1000))
#        self._current_user = User(key_name="1031417530"+str(rand),id="1031417530"+str(rand),name="Alon Gutman"+str(rand),profile_url="http://www.facebook.com/profile.php?id=1031417530",
#                                access_token="177865318892435|2.xyUNl3CKpPWw12D_9sCQ4A__.3600.1296316800-1031417530|XPgohFojcOjdedoPNmQZCy_bRb0")
#        self._current_user.put()
#        return self._current_user
        ###### end temp
        
        if not hasattr(self, "_current_user"):
            self._current_user = None
            cookie = facebook.get_user_from_cookie(
                self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
            if cookie:
                # Store a local instance of the user data so we don't need
                # a round-trip to Facebook on every request
                user = User.get_by_key_name(cookie["uid"])
                if not user:
                    graph = facebook.GraphAPI(cookie["access_token"])
                    profile = graph.get_object("me")
                    user = User(key_name=str(profile["id"]),
                                id=str(profile["id"]),
                                name=profile["name"],
                                profile_url=profile["link"],
                                access_token=cookie["access_token"])
                    user.put()
                elif user.access_token != cookie["access_token"]:
                    user.access_token = cookie["access_token"]
                    user.put()
                self._current_user = user
        return self._current_user
    
    # simple methods:
    def getText(self,name):
        return self.request.get(name)
    
    def getNum(self,name):
        res = self.request.get(name)
        if res == "" or res == None:
            return None
        return int(res)
    
    def sendResponse(self,file,page,values):
        path = os.path.join(os.path.dirname(file), page)
        self.response.out.write(template.render(path, values))


# gu methods:
def toList(myIterable):
    '''
    convert iterable to list.
    '''
    myList = []
    for it in myIterable:
        myList.append(it)
    return myList

        
application = webapp.WSGIApplication([(r'/(.*)', MyBaseHandler)], debug=True)


def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()



